<template>
  <transition name="slide">
    <nav v-if="visible" class="menu">
      <div class="menu-content">
        <div class="menu-item-container">
          <NuxtLink class="menu-item" exact-active-class="selected" to="/" @click="handleItemClick">
            <i class="menu-item-icon fas fa-hashtag"></i>
            <span class="menu-item-text">话题</span>
          </NuxtLink>
          <NuxtLink
            class="menu-item"
            exact-active-class="selected"
            to="/new-post"
            @click="handleItemClick"
          >
            <i class="menu-item-icon fas fa-edit"></i>
            <span class="menu-item-text">发帖</span>
          </NuxtLink>
          <NuxtLink
            class="menu-item"
            exact-active-class="selected"
            to="/message"
            @click="handleItemClick"
          >
            <i class="menu-item-icon fas fa-envelope"></i>
            <span class="menu-item-text">我的消息</span>
            <span v-if="unreadCount > 0" class="unread-container">
              <span class="unread"> {{ showUnreadCount }} </span>
            </span>
          </NuxtLink>
          <NuxtLink
            class="menu-item"
            exact-active-class="selected"
            to="/about"
            @click="handleItemClick"
          >
            <i class="menu-item-icon fas fa-info-circle"></i>
            <span class="menu-item-text">关于</span>
          </NuxtLink>
          <NuxtLink
            class="menu-item"
            exact-active-class="selected"
            to="/activities"
            @click="handleItemClick"
          >
            <i class="menu-item-icon fas fa-gift"></i>
            <span class="menu-item-text">🔥 活动</span>
          </NuxtLink>
          <NuxtLink
            v-if="shouldShowStats"
            class="menu-item"
            exact-active-class="selected"
            to="/about/stats"
            @click="handleItemClick"
          >
            <i class="menu-item-icon fas fa-chart-line"></i>
            <span class="menu-item-text">站点统计</span>
          </NuxtLink>
          <NuxtLink
            v-if="authState.loggedIn"
            class="menu-item"
            exact-active-class="selected"
            to="/points"
            @click="handleItemClick"
          >
            <i class="menu-item-icon fas fa-coins"></i>
            <span class="menu-item-text">
              积分商城
              <span v-if="myPoint !== null" class="point-count">{{ myPoint }}</span>
            </span>
          </NuxtLink>
        </div>

        <div class="menu-section">
          <div class="section-header" @click="categoryOpen = !categoryOpen">
            <span>类别</span>
            <i :class="categoryOpen ? 'fas fa-chevron-up' : 'fas fa-chevron-down'"></i>
          </div>
          <div v-if="categoryOpen" class="section-items">
            <div v-if="isLoadingCategory" class="menu-loading-container">
              <l-hatch size="28" stroke="4" speed="3.5" color="var(--primary-color)"></l-hatch>
            </div>
            <div
              v-else
              v-for="c in categoryData"
              :key="c.id"
              class="section-item"
              @click="gotoCategory(c)"
            >
              <template v-if="c.smallIcon || c.icon">
                <BaseImage
                  v-if="isImageIcon(c.smallIcon || c.icon)"
                  :src="c.smallIcon || c.icon"
                  class="section-item-icon"
                  :alt="c.name"
                />
                <i v-else :class="['section-item-icon', c.smallIcon || c.icon]"></i>
              </template>
              <span class="section-item-text">
                {{ c.name }}
                <span class="section-item-text-count" v-if="c.count >= 0">x {{ c.count }}</span>
              </span>
            </div>
          </div>
        </div>

        <div class="menu-section">
          <div class="section-header" @click="tagOpen = !tagOpen">
            <span>标签</span>
            <i :class="tagOpen ? 'fas fa-chevron-up' : 'fas fa-chevron-down'"></i>
          </div>
          <div v-if="tagOpen" class="section-items">
            <div v-if="isLoadingTag" class="menu-loading-container">
              <l-hatch size="28" stroke="4" speed="3.5" color="var(--primary-color)"></l-hatch>
            </div>
            <div v-else v-for="t in tagData" :key="t.id" class="section-item" @click="gotoTag(t)">
              <BaseImage
                v-if="isImageIcon(t.smallIcon || t.icon)"
                :src="t.smallIcon || t.icon"
                class="section-item-icon"
                :alt="t.name"
              />
              <i v-else class="section-item-icon fas fa-hashtag"></i>
              <span class="section-item-text"
                >{{ t.name }} <span class="section-item-text-count">x {{ t.count }}</span></span
              >
            </div>
          </div>
        </div>
      </div>

      <!-- 解决动态样式的水合错误 -->
      <ClientOnly v-if="!isMobile">
        <div class="menu-footer">
          <div class="menu-footer-btn" @click="cycleTheme">
            <i :class="iconClass"></i>
          </div>
        </div>
      </ClientOnly>
    </nav>
  </transition>
</template>

<script setup>
import { computed, onMounted, ref, watch } from 'vue'
import { authState, fetchCurrentUser } from '~/utils/auth'
import { fetchUnreadCount, notificationState } from '~/utils/notification'
import { useIsMobile } from '~/utils/screen'
import { cycleTheme, ThemeMode, themeState } from '~/utils/theme'

const isMobile = useIsMobile()

const config = useRuntimeConfig()
const API_BASE_URL = config.public.apiBaseUrl

const props = defineProps({
  visible: { type: Boolean, default: true },
})
const emit = defineEmits(['item-click'])

const categoryOpen = ref(true)
const tagOpen = ref(true)
const myPoint = ref(null)

/** ✅ 用 useAsyncData 替换原生 fetch，避免 SSR+CSR 二次请求 */
const {
  data: categoryData,
  pending: isLoadingCategory,
  error: categoryError,
} = await useAsyncData(
  // 稳定 key：避免 hydration 期误判
  'menu:categories',
  () => $fetch(`${API_BASE_URL}/api/categories`),
  {
    server: true, // SSR 预取
    default: () => [], // 初始默认值，减少空判断
    // 5 分钟内复用缓存，避免路由往返重复请求
    staleTime: 5 * 60 * 1000,
  },
)

const {
  data: tagData,
  pending: isLoadingTag,
  error: tagError,
} = await useAsyncData('menu:tags', () => $fetch(`${API_BASE_URL}/api/tags?limit=10`), {
  server: true,
  default: () => [],
  staleTime: 5 * 60 * 1000,
})

/** 其余逻辑保持不变 */
const iconClass = computed(() => {
  switch (themeState.mode) {
    case ThemeMode.DARK:
      return 'fas fa-moon'
    case ThemeMode.LIGHT:
      return 'fas fa-sun'
    default:
      return 'fas fa-desktop'
  }
})

const unreadCount = computed(() => notificationState.unreadCount)
const showUnreadCount = computed(() => (unreadCount.value > 99 ? '99+' : unreadCount.value))
const shouldShowStats = computed(() => authState.role === 'ADMIN')

const loadPoint = async () => {
  if (authState.loggedIn) {
    const user = await fetchCurrentUser()
    myPoint.value = user ? user.point : null
  } else {
    myPoint.value = null
  }
}

const updateCount = async () => {
  if (authState.loggedIn) {
    await fetchUnreadCount()
  } else {
    notificationState.unreadCount = 0
  }
}

onMounted(async () => {
  await Promise.all([updateCount(), loadPoint()])
  // 登录态变化时再拉一次未读数和积分；与 useAsyncData 无关
  watch(
    () => authState.loggedIn,
    () => {
      updateCount()
      loadPoint()
    },
  )
})

const handleItemClick = () => {
  if (window.innerWidth <= 768) emit('item-click')
}

const isImageIcon = (icon) => {
  if (!icon) return false
  return /^https?:\/\//.test(icon) || icon.startsWith('/')
}

const gotoCategory = (c) => {
  const value = encodeURIComponent(c.id ?? c.name)
  navigateTo({ path: '/', query: { category: value } }, { replace: true })
  handleItemClick()
}

const gotoTag = (t) => {
  const value = encodeURIComponent(t.id ?? t.name)
  navigateTo({ path: '/', query: { tags: value } }, { replace: true })
  handleItemClick()
}
</script>

<style scoped>
.menu {
  position: sticky;
  top: var(--header-height);
  width: 220px;
  background-color: var(--app-menu-background-color);
  height: calc(100vh - var(--header-height));
  border-right: 1px solid var(--menu-border-color);
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  scrollbar-width: none;
  backdrop-filter: var(--blur-10);
}

.menu-content {
  width: 100%;
  height: 100%;
  overflow-y: auto;
  box-sizing: border-box;
  padding: 10px 10px 0 10px;
}

.menu-content::-webkit-scrollbar {
  display: none;
}

.menu-content {
  -ms-overflow-style: none;
  scrollbar-width: none;
}

.menu-item-container {
  border-bottom: 1px solid var(--menu-border-color);
}

.menu-item:last-child {
  margin-bottom: 5px;
}

/* .menu-item-container { */
/**/
/* } */

.menu-item {
  padding: 6px 12px;
  text-decoration: none;
  color: var(--menu-text-color);
  border-radius: 10px;
  display: flex;
  align-items: center;
}

.menu-item.selected {
  font-weight: bold;
  background-color: var(--menu-selected-background-color);
}

.menu-item-text {
  font-size: 14px;
  text-decoration: none;
  color: var(--menu-text-color);
}

.unread-container {
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background-color: rgb(255, 102, 102);
  margin-left: 15px;
  width: 18px;
  height: 18px;
  text-align: center;
}

.unread {
  color: white;
  font-size: 9px;
  font-weight: bold;
}

.point-count {
  margin-left: 4px;
  font-size: 12px;
  color: var(--primary-color);
}

.menu-item-icon {
  margin-right: 10px;
  opacity: 0.5;
  font-weight: bold;
}

.menu-footer {
  position: relation;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: flex-end;
}

.menu-footer-btn {
  width: 30px;
  height: 30px;
  margin-right: 5px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.menu-section {
  border-bottom: 1px solid var(--menu-border-color);
  padding-bottom: 5px;
}

.section-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 14px;
  padding: 6px 12px 0 12px;
  color: var(--menu-text-color);
  cursor: pointer;
}

.section-items {
  color: var(--menu-text-color);
  display: flex;
  flex-direction: column;
  margin-top: 4px;
}

.section-item {
  padding: 6px 12px;
  display: flex;
  align-items: center;
  gap: 5px;
  border-radius: 8px;
  cursor: pointer;
}

.section-item:hover {
  background-color: var(--menu-selected-background-color);
}

.section-item-text-count {
  font-size: 12px;
  color: var(--menu-text-color);
  opacity: 0.5;
  font-weight: bold;
}

.section-item-text {
  font-size: 14px;
  text-decoration: none;
  color: var(--menu-text-color);
}

.section-item-icon {
  width: 16px;
  height: 16px;
  margin-right: 5px;
  opacity: 0.7;
}

.menu-loading-container {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 10px;
}

@media (max-width: 768px) {
  .menu {
    position: fixed;
    z-index: 1000;
    box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.1);
    left: 10px;
    border-radius: 20px;
    border-right: none;
    height: 400px;
    top: calc(var(--header-height) + 10px);
    padding-top: 10px;
    background-color: var(--background-color-blur);
  }

  .menu-content {
    border-radius: 20px;
  }

  .slide-enter-active,
  .slide-leave-active {
    transition:
      transform 0.3s ease,
      opacity 0.3s ease,
      width 0.3s ease;
  }

  .slide-enter-from,
  .slide-leave-to {
    transform: translateX(-100%);
    opacity: 0;
  }

  .slide-enter-to,
  .slide-leave-from {
    transform: translateX(0);
    opacity: 1;
  }
}
</style>
